// 将时间长度转成多少h多少s
function convertMillicountsToHMS(time) {
  let seconds = Math.floor(time);
  let minutes = Math.floor(seconds / 60);
  let hours = Math.floor(minutes / 60);

  seconds %= 60;
  minutes %= 60;
  // hours %= 24;

  // console.log('hours',hours,'minutes',minutes,'seconds',seconds)
  // 将小时、分钟、秒转换为字符串并保证至少有两位数字
  let hourStr = ("0" + hours).slice(-2);
  let minuteStr = ("0" + minutes).slice(-2);
  let countstr = ("0" + seconds).slice(-2);

  if (hours > 0) {
    return `${hourStr}:${minuteStr}:${countstr}`;
  }

  return `${minuteStr}:${countstr}`;
}

// 获取每个刻度线之间的多少秒（画刻度）
// 时间从0开始，按照6的倍数去算一刻度多少秒合适[1,6,12,18....]
// 设定刻度
const getScaleLineMinute = (time, width) => {
  if (!time || !width) {
    return 1;
  }
  let scaleLine_second;
  for (let i = 0; i < time; i++) {
    const currentLineSecond = Math.max(1, i * 6);
    const perWidth = (width / time) * currentLineSecond;
    if (perWidth >= MINPERWIDTH && perWidth <= MAXPERWIDTH) {
      scaleLine_second = currentLineSecond;
      break;
    }
  }
  // 没找到刻度距离合适的
  if (!scaleLine_second) {
    // 如果没有合适就1s一刻度
    return 1;
  }
  return scaleLine_second;
};

let _id = 0;
const uniId = () => {
  return _id + 1; // 模拟id生成
};

// 绘画配置
const Colors = {
  color: "#fff",
  background: "#333", //背景
  markColor: "rgba(64,158,255,0.5)",

  //中间线
  meddleLine: "#33CC33",
  //移动线
  moveLine: "#808080",
  //移动时间
  moveDate: "#009966",
  //刻度线
  scaleLine: "#808080",
};

const secondGapList = [1, 5, 10, 24]; // 刻度线间隔

// 刻度的间隔距离范围（px）
const MINPERWIDTH = 10;
const MAXPERWIDTH = 50;
// 缩放范围
const MINSCALE = 1;
const MAXSCALE = 5;

const Heights = {
  line: 0.15, // 短线
  lineHigh: 0.25, // 长线
  lineText: 0.4, // 刻度文字
  moveLine: 0.8, // 移动的线
  moveText: 0.9, // 移动的数
  mark: 1,
};

class Ruler {
  /**
   * 初始化刻度尺插件
   * @el 容器 String
   * @height 刻度尺高度 Number
   * @time 绘画的时长 Number
   * */

  constructor(params) {
    // 构建函数传参
    const {
      time,
      el,
      height,
      addRegion,
      addTempPosition,
      disabled = false,
      regions = [],
    } = params;

    this.canvas = el;
    this.displayWidth =
      this.canvas?.parentElement?.clientWidth || document.body.clientWidth; // 容器宽度
    this.scaleWidth = 1; // x缩放量
    this.canvasWidth = this.displayWidth * this.scaleWidth; // 画布的宽度
    this.height = height; // 容器高度
    this.px_second = 0; // 每个像素点对应多少秒（像素转时间和刻度）
    this.ctx = this.canvas.getContext("2d"); // canvas 上下文
    this.time = time; // 秒数
    this.scaleLine_second = getScaleLineMinute(time, this.canvasWidth); // 1 个刻度代表ns

    this.mousePositions = []; //  鼠标点击两次的距离合集
    this.markList = regions; //  点击打框

    this.scrollLeft = 0; // 画布的偏移量
    // 移动时鼠标有没有按下
    this.isMouseDown = false;
    // 鼠标按下时有没有移动
    this.isMove = false;
    this.disabled = disabled;

    this.mouseData = { startX: 0, startY: 0 };

    // 监听事件
    this.listenEvents();

    this.addRegion = addRegion; // 更新事件
    this.addTempPosition = addTempPosition; // 画第一条刻度
  }

  init() {
    this.displayWidth =
      this.canvas?.parentElement?.clientWidth || document.body.clientWidth; // 容器宽度
    if (this.time === 0 || !this.displayWidth) {
      return;
    }
    this.render();
  }

  render() {
    this.canvasWidth = Math.floor(this.displayWidth * this.scaleWidth);
    // 1. 计算像素和时间比
    this.scaleLine_second = getScaleLineMinute(this.time, this.canvasWidth); // 1 个刻度代表ns
    this.px_second = this.time / this.canvasWidth;
    // 设置画布大小
    this.canvas.width = this.canvasWidth;
    this.canvas.height = this.height;

    // 2. 绘制图表
    this.draw();
  }

  listenEvents() {
    // 鼠标悬浮事件
    this.canvas.addEventListener("mousemove", (e) => {
      this.mousemove(e);
    });
    // resize 事件
    window.addEventListener(
      "resize",
      () => {
        this.resize();
      },
      false
    );
    // 鼠标点击事件
    this.canvas.addEventListener("mousedown", (e) => {
      this.mousedown(e);
    });
    this.canvas.addEventListener("mouseup", (e) => {
      this.mouseup(e);
    });
    this.canvas.addEventListener("mouseleave", (e) => {
      this.mouseleave(e);
    });
    this.canvas.addEventListener("mousewheel", this.scrollWheelFunc, {
      passive: false,
    });
  }

  disposed() {
    // 注销事件监听
    this.canvas.onmousemove = null;
    window.onresize = null;
  }

  draw() {
    this.drawScaleLine();
    this.drawMark();
  }

  drawScaleLine() {
    const ctx = this.ctx;
    //刻度尺背景
    ctx.fillStyle = Colors.background;
    ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
    ctx.font = "14px Arial";
    ctx.fillStyle = Colors.color;
    ctx.textAlign = "center";
    ctx.textBaseline = "middle";

    // 每条线之间的间隔 scaleLine_second来确定每个格代表多长时间
    const line_px = this.scaleLine_second / this.px_second;
    let count = 0;
    //画刻度线
    for (let i = 0; i < this.canvasWidth; i += line_px) {
      if (i === 0) {
        ctx.textAlign = "left";
      }
      ctx.beginPath();
      ctx.save();
      ctx.strokeStyle = Colors.color;
      ctx.lineWidth = 1;
      ctx.lineCap = "round";
      // 绘制的x坐标
      const x = i;

      ctx.moveTo(x, 0);
      ctx.lineTo(x, Math.floor(this.height * Heights.line));

      const time = count * this.scaleLine_second;

      // 获取绘制的点 秒的时候相隔5,如果刻度比最小范围还小，则10刻度现实一个文案,如果刻度大于最大范围则每刻度都展示一个文案
      let bool = count % 5 === 0;
      if (line_px > MAXPERWIDTH) {
        bool = true;
      }
      if (line_px < MINPERWIDTH) {
        bool = count % 10 === 0;
      }
      if (bool) {
        ctx.lineTo(x, Math.floor(this.height * Heights.lineHigh));

        // 总时长大于1小时的时候，文字太长，跳列展示文字
        if (this.time < 60 * 60 || count % 2 === 0) {
          // 添加文字
          ctx.fillText(
            convertMillicountsToHMS(time),
            x,
            Math.floor(this.height * Heights.lineText)
          );
        }
      }

      ctx.stroke();
      // ctx.restore();
      // ctx.closePath();

      count++; // 计算刻度数
      if (i === 0) {
        ctx.textAlign = "center";
      }
    }
  }

  // 画标记的时间
  drawMark() {
    const ctx = this.ctx;

    // 画canvas上部分的颜色
    this.markList.forEach((item) => {
      ctx.fillStyle = item.bgColor || Colors.markColor;
      const { start: startTime, end: endTime } = item;
      const start = Math.floor(startTime / this.px_second);
      const end = Math.floor(endTime / this.px_second);
      ctx.fillRect(start, 0, end - start, this.height * Heights.mark);
    });
    ctx.save();
    ctx.stroke();
  }

  setScrollLeft(scrollLeft) {
    this.scrollLeft = scrollLeft;
    if (this.canvas.parentElement) {
      this.canvas.parentElement.scrollTo(scrollLeft, 0);
    }
  }

  move(e) {
    const deltaX = this.mouseData.startX - e.offsetX;
    const length = this.scrollLeft + deltaX;
    this.setScrollLeft(length);
  }

  // 画鼠标移上去的线
  mousemove(e) {
    this.draw();

    if (this.isMouseDown) {
      this.isMove = true;
      this.move(e);
    }

    let offetTime = Math.floor(e.offsetX * this.px_second);

    const time = convertMillicountsToHMS(offetTime);
    const ctx = this.ctx;
    if (!ctx) {
      return;
    }

    ctx.beginPath();
    ctx.moveTo(e.offsetX - 1, 0);
    ctx.lineTo(e.offsetX - 1, Math.floor(this.height * Heights.moveLine));
    ctx.strokeStyle = Colors.moveLine;
    ctx.lineWidth = 1;
    ctx.stroke();
    ctx.fillStyle = Colors.moveDate;

    ctx.font = `${12}px serif`;
    ctx.fillText(
      time,
      e.offsetX - 50,
      Math.floor(this.height * Heights.moveText)
    );
  }

  // 鼠标按下
  mousedown(e) {
    if (!e.offsetX) {
      return;
    }
    this.isMouseDown = true;
    this.isMove = false;

    // 判断移动起点
    this.mouseData = {
      startX: e.offsetX,
      startY: e.offsetY,
    };
  }

  // 抬起鼠标
  mouseup(e) {
    this.isMouseDown = false;
    if (this.disabled) {
      return;
    }
    // 没有滑动或鼠标移动(视为点击操作)，就渲染中间时间（另外的是在移动事件里渲染）。
    if (!this.isMove) {
      this.mousePositions.push(e.offsetX);

      if (this.mousePositions.length === 1) {
        // 绘制刻度线第一条
        this.addTempPosition && this.addTempPosition(e.offsetX);
      } else {
        this.addTempPosition && this.addTempPosition(0);
      }
    } else {
      this.mousePositions = [];
      this.addTempPosition && this.addTempPosition(0);
    }
    if (!this.isMove && this.mousePositions.length === 2) {
      const startTime = this.mousePositions[0] * this.px_second;
      const endTime = this.mousePositions[1] * this.px_second;

      const newItem = {
        start: startTime,
        end: endTime,
        id: uniId(),
      };
      this.markList.push(newItem);

      // 重新制为0
      this.mousePositions = [];
      this.draw();
      // 释放时确定时间选择
      this.addRegion(newItem);
    }
  }

  //鼠标离开
  mouseleave(e) {
    //鼠标离开无法在触发mouseup，所以当拖动时将离开视释放
    if (this.isMouseDown) {
      this.mouseup(e);
    } else {
      this.isMouseDown = false;
    }
  }

  resize() {
    //有时屏幕尺寸变化了，而容器的尺寸还未改变的情况下的处理
    if (
      this.canvas.style.width ===
      this.canvas.parentElement.clientWidth + "px"
    ) {
      setTimeout(() => {
        this.resize();
      }, 10);
    } else {
      //重新初始化
      this.init();
    }
  }

  setTime(time) {
    this.time = time;
    this.init();
  }

  // 缩放
  onScale(flag) {
    let newScale = flag ? this.scaleWidth + 0.2 : this.scaleWidth - 0.2;
    if (newScale > MAXSCALE) {
      return;
    }
    if (newScale < MINSCALE) {
      // newScale = 1;
      return;
    }
    const lastCenterScrollLeft = this.scrollLeft + this.displayWidth / 2;
    const newScrollLeft =
      (lastCenterScrollLeft * newScale) / this.scaleWidth -
      this.displayWidth / 2;
    this.setScrollLeft(newScrollLeft);
    this.scaleWidth = newScale;
    this.render();
  }

  scrollWheelFunc = (event) => {
    if (event.wheelDelta > 0 || event.detail < 0) {
      this.onScale(1);
    } else {
      this.onScale(0);
    }
  };

  // 删除
  deleteMark = (id) => {
    const index = this.markList.findIndex((e) => e.id === id);
    if (index === -1) {
      return;
    }
    this.markList.splice(index, 1);
    this.draw();
  };

  updateRegion = (region) => {
    const { start, end, id } = region;
    if (!start && !end) {
      return;
    }
    const index = this.markList.findIndex((e) => e.id === id);
    if (index > -1) {
      this.markList.splice(index, 1, { start, end, id });
      this.draw();
      return true;
    }
    return false;
  };

  setDisabled = (val) => {
    this.disabled = val;
  };

  setMarkList = (regions) => {
    this.markList = JSON.parse(JSON.stringify(regions));
    this.draw();
  };

  getter(name) {
    return this[name];
  }
}
